package com.quectel.sdk.emq;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.quectel.sdk.emq.bean.EmqConfigProperty;
import com.quectel.sdk.emq.bean.EmqResponse;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.http.HttpRestUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;

import java.nio.charset.Charset;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 在这里编写说明
 *
 * @author: rananxin
 * @email: ryan.ran@quectel.com
 * @date: 2022-10-19 11:01:00
 */
@Slf4j
public class EmqRestUtils {

    private static final HttpRestUtils HTTP_REST_UTILS = HttpRestUtils.getDefaultInstance();

    private EmqConfigProperty emqConfigProperty;

    private EmqRestUtils() {
    }

    ;

    private EmqRestUtils(EmqConfigProperty emqConfigProperty) {
        this.emqConfigProperty = emqConfigProperty;
    }

    public static EmqRestUtils getInstance(EmqConfigProperty emqConfigProperty) {
        return new EmqRestUtils(emqConfigProperty);
    }

    public List<EmqResponse.GetResourcesResponse> getResourcesList() {
        EmqResponse response = request(emqConfigProperty.getUrl(), EmqApiEnum.GET_RESOURCES_LIST, new HashMap<>());
        List<EmqResponse.GetResourcesResponse> list = new ArrayList<>();
        if (response.isSuccess()) {
            String data = response.getData();
            if (StringUtils.isNotBlank(data)) {
                list = JacksonUtils.parseArray(data, JsonNode.class).stream().map(o -> {
                    JsonNode itemJson = (JsonNode) o;
                    EmqResponse.GetResourcesResponse resourcesResponse = new EmqResponse.GetResourcesResponse();
                    resourcesResponse.setResourceId(itemJson.get("id").asText());
                    resourcesResponse.setCallbackUrl(itemJson.findValue("config").get("url").asText());
                    return resourcesResponse;
                }).collect(Collectors.toList());
            }
        }
        return list;
    }

    public EmqResponse addResource(String callBackUrl) {
        Map<String, Object> params = new HashMap<>();
        EmqResponse response = request(emqConfigProperty.getUrl(), EmqApiEnum.ADD_RESOURCES, params);
        return response;
    }

    private EmqResponse request(String url
            , EmqApiEnum methodEnum
            , Map<String, Object> params) {

        String path = methodEnum.getPath();
        String filledUrl = fillPath(url + path, params);

        Map<String, String> headers = getHeader(emqConfigProperty.getUsername(), emqConfigProperty.getPassword());

        EmqResponse emqResponse = null;
        try {
            String response = StrUtil.EMPTY;
            switch (methodEnum.getReqMethod()) {
                case "GET":
                    List<NameValuePair> paramList = new ArrayList<>();
                    if (params != null) {
                        Set<Map.Entry<String, Object>> entries = params.entrySet();
                        for (Map.Entry<String, Object> entry : entries) {
                            paramList.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())));
                        }
                    }
                    response = (String) HTTP_REST_UTILS.get(filledUrl, paramList, headers, new TypeReference<String>() {
                    }).getRight();
                    break;
                case "POST":
                    response = (String) HTTP_REST_UTILS.post(filledUrl, params, headers, new TypeReference<String>() {
                    }).getRight();
                    break;
                case "PUT":
                    response = (String) HTTP_REST_UTILS.put(filledUrl, params, headers, new TypeReference<String>() {
                    }).getRight();
                    break;
                case "DELETE":
                    response = (String) HTTP_REST_UTILS.delete(filledUrl, params, headers, new TypeReference<String>() {
                    }).getRight();
                    break;
                default:
                    break;
            }

            emqResponse = JacksonUtils.parse(response, EmqResponse.class);
        } catch (Exception e) {
            log.error("Exception", e);
        }
        return emqResponse;
    }

    @AllArgsConstructor
    public enum EmqApiEnum {
        UPDATE_ACCOUNT("PUT", "api/v4/change_pwd/{account}", "更改控制台账号"),
        GET_SUB_LIST("GET", "api/v4/subscriptions", "获取订阅列表"),
        DEL_APP("DELETE", "api/v4/apps/{appId}", "删除应用"),
        PUB_MSG("POST", "api/v4/mqtt/publish", "发布消息"),
        ADD_RESOURCES("POST", "api/v4/resources", "添加资源"),
        GET_RESOURCES_LIST("GET", "api/v4/resources", "获取资源列表"),
        DEL_RESOURCES("DELETE", "api/v4/resources/{resourceId}", "删除资源");


        @Getter
        private String reqMethod;
        @Getter
        private String path;
        @Getter
        private String desc;

    }


    private String fillPath(String path, Map<String, Object> params) {
        for (String key : params.keySet()) {
            String goal = "{" + key + "}";
            if (path.indexOf(goal) > 0) {
                path = path.replace(goal, params.get(key).toString());
            }
        }
        return path;
    }

    private Map<String, String> getHeader(String account, String password) {
        String auth = account + ":" + password;
        byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(Charset.forName("US-ASCII")));
        String authStr = "Basic " + new String(encodedAuth);
        Map<String, String> map = new HashMap<>();
        map.put("Authorization", authStr);
        return map;
    }

}
